# !/usr/bin/env python
# -*- coding: utf-8 -*-

import functools
import hashlib
import logging
import socket
import time
from concurrent.futures import ThreadPoolExecutor

import tornado
# from tornado.web import asynchronous

from conf import config
from conf.config import MAX_WORKERS, MP_TOKEN, DEBUG
from conf.logging import LOG_FULL_PATH
from helper.exceptions import RequestEnd

logger = logging.getLogger("wechat")
THREAD_POOL = ThreadPoolExecutor(max_workers=MAX_WORKERS)


def time_of_function(method):
    """
    检测函数的运行时间
    :param method:
    :return:
    """
    try:
        def _wrapper(*args, **kwargs):
            start = time.clock()
            method(*args, **kwargs)
            print("%s cost %s second" % (method.__name__, time.clock() - start))

        return _wrapper
    except Exception as e:
        logging.error(e)


def wechat_authenticated(method):
    """
    验证请求来源(来源至微信)
    :param method:
    :return:
    """
    try:
        @functools.wraps(method)
        def wrapper(self, *args, **kwargs):
            # 调试模式(无需微信请求认证)
            if config.DEBUG and isinstance(config.DEBUG, bool):
                return method(self, *args, **kwargs)
            # 正式模式
            signature = self.get_argument("signature", "")
            timestamp = self.get_argument("timestamp", "")
            nonce = self.get_argument("nonce", "")

            temp_list = [MP_TOKEN, timestamp, nonce]
            temp_list.sort()
            temp_str = ''.join(temp_list)
            temp_str = hashlib.sha1(temp_str.encode('utf8')).hexdigest()

            if temp_str == signature:
                return method(self, *args, **kwargs)
            else:
                return self.finish("hi!")

        return wrapper
    except Exception as e:
        logging.error(e)


def maintenance_authenticated(method):
    """
    验证是否为维护人员
    :param method:
    :return:
    """
    try:
        @functools.wraps(method)
        def wrapper(self, *args, **kwargs):
            if not config.DEBUG:
                mid = self.get_secure_cookie("mid")
                if not mid:
                    return self.redirect("/auth")
            return method(self, *args, **kwargs)

        return wrapper
    except Exception as e:
        logger.exception(e)


def asyncs(f):
    """
    异步装饰器，避免阻塞主handler
    :param f:
    :return:
    """

    # @asynchronous
    @functools.wraps(f)
    def wrapper(*args, **kwargs):
        self = args[0]
        self._auto_finish = False

        async def callback(future):
            if self._finished:
                return
            try:
                result = future.result()
                if result is not None:
                    if str(type(result)) == "<class 'coroutine'>" and not self._finished:
                        result = await result
                    if isinstance(result, bytes) or isinstance(result, str) or isinstance(result, dict):
                        self.write(result)
            except Exception as e:
                if not isinstance(e, RequestEnd):
                    logger.exception(e)
                if DEBUG:
                    if not self._finished:
                        self.write(str(e))
                else:
                    if not self._finished:
                        self.write("server error! for more information , see the server %s's log!(%s)" % (
                            socket.gethostname(), LOG_FULL_PATH))
                    pass
            if not self._finished:
                self.finish()

        THREAD_POOL.submit(functools.partial(f, *args, **kwargs)).add_done_callback(
            lambda future: tornado.ioloop.IOLoop.current().add_callback(
                functools.partial(callback, future)))

    return wrapper
